#include "gl_util.h"
#include <gl/GLU.h>
#include <cmath>

namespace util { namespace gl {
  const color color::black(0, 0, 0);
  const color color::white(255, 255, 255);

  void draw_axis(const axis &a, QGLWidget *p_widget, const QFont &font)
  {
    const char *p_ver = (const char *) gluGetString(GLU_VERSION);
    GLdouble vector_begin_prj[3];
    GLdouble vector_end_prj[3];
    glBegin(GL_LINES);
    glVertex3dv(a.vector_begin);
    glVertex3dv(a.vector_end);
    glEnd();

    GLdouble model_matrix[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
    GLdouble projection_matrix[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
    GLint viewport[4] = { -1, -1, 2, 2 };

    glGetDoublev(GL_MODELVIEW_MATRIX, model_matrix);
    glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
    glGetIntegerv(GL_VIEWPORT, viewport);

    gluProject(a.vector_begin[0], a.vector_begin[1], a.vector_begin[2], model_matrix, projection_matrix, viewport, &vector_begin_prj[0], &vector_begin_prj[1], &vector_begin_prj[2]);
    gluProject(a.vector_end[0], a.vector_end[1], a.vector_end[2], model_matrix, projection_matrix, viewport, &vector_end_prj[0], &vector_end_prj[1], &vector_end_prj[2]);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(viewport[0], viewport[0] + viewport[2], viewport[1], viewport[1] + viewport[3]);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    const GLdouble dx = vector_end_prj[0] - vector_begin_prj[0];
    const GLdouble dy = vector_end_prj[1] - vector_begin_prj[1];
    const GLdouble d = sqrt(dx * dx + dy * dy);
    { // new model view matrix
      GLdouble model_matrix[16] = {
        dx, dy, 0.0, 0.0,
        -dy / d, dx / d, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        vector_begin_prj[0], vector_begin_prj[1], 0.0, 1.0
      };
      glLoadMatrixd(model_matrix);
    }
    glBegin(GL_LINES);
    glVertex2f(0, 0);
    glVertex2f(1, 0);
    glEnd();
    QFontMetrics font_metrics(font);
    const qreal tick_min_space = font_metrics.height() * 1.5; // minimal space between ticks
    const qreal min_step = (a.value_transform(1) - a.value_transform(0)) / (d / tick_min_space); // minimal value step for current view
    const qreal step = max(a.value_step, floor(min_step / a.value_step) * a.value_step);
    const long ind_min = int(a.value_transform(0) / step);
    const long ind_max = int(a.value_transform(1) / step);
    LinearTransform inv = a.value_transform.Invert();
    long ind = ind_min;
    for (long ind = ind_min; ind <= ind_max; ++ind)
    {
      const GLfloat x = inv(ind * step);
      glBegin(GL_LINES);
      glVertex2f(x, -10);
      glVertex2f(x, 10);
      glEnd();
//      for (int i = 0; i < 10; ++i)
//        p_widget->renderText(100, 100, QString("aaa"), font);
    }
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
  }
} } // namespace util { namespace gl {